package cn.gov.pbc.gd.credit.provider.api.log.impl;

import java.io.Serializable;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import com.liu.jbase.PageListVo;
import com.liu.jbase.service.mongo.IMongoClient;

import cn.gov.pbc.gd.credit.api.log.ILogOperateApi;
import cn.gov.pbc.gd.credit.vo.log.LogOperateVo;

@Service
public class LogOperateApiImpl implements ILogOperateApi {

	@Autowired
	private IMongoClient<LogOperateVo> mongoClient;

	@Override
	public void insert(LogOperateVo entity) throws Exception {
		mongoClient.insert(entity);
	}

	@Override
	public void updateById(Serializable id, String key, String value) throws Exception {

		mongoClient.updateById(id, key, value, LogOperateVo.class);
	}

	@Override
	public void update(LogOperateVo vo) throws Exception {
		mongoClient.update(vo);
	}

	@Override
	public void update(LogOperateVo vo, String key, String value) throws Exception {

		Query query = new Query();

		mongoClient.update(query, key, value, LogOperateVo.class);

	}

	@Override
	public void deleteById(Serializable id) throws Exception {
		mongoClient.deleteById(id, LogOperateVo.class);

	}

	@Override
	public void deleteByQuery(LogOperateVo vo) throws Exception {

		Query query = new Query();

		mongoClient.deleteByQuery(query, LogOperateVo.class);

	}

	@Override
	public LogOperateVo getOneById(Serializable id) throws Exception {

		return mongoClient.getOneById(id, LogOperateVo.class);
	}

	@Override
	public LogOperateVo getOne(LogOperateVo vo) throws Exception {

		Query query = new Query();

		return mongoClient.getOne(query, LogOperateVo.class);
	}

	@Override
	public List<LogOperateVo> getAll(Class<LogOperateVo> entity) throws Exception {
		return mongoClient.getAll(entity);
	}

	@Override
	public List<LogOperateVo> getAll(LogOperateVo vo) throws Exception {

		Query query = new Query();

		return mongoClient.getAll(query, LogOperateVo.class);
	}

	@Override
	public long getCount(LogOperateVo vo) throws Exception {

		Query query = new Query();

		return mongoClient.getCount(query, LogOperateVo.class);
	}

	@Override
	public PageListVo<LogOperateVo> getPage(LogOperateVo vo, PageListVo<LogOperateVo> page) throws Exception {

		setTimeFromString(vo);

		Query query = new Query();

		if (vo.getAccount() != null && vo.getAccount() != "" && vo.getAccount().length() > 0) {// 1.账号

			Pattern pattern = Pattern.compile("^.*" + vo.getAccount() + ".*$", Pattern.CASE_INSENSITIVE);

			query.addCriteria(Criteria.where("account").regex(pattern));
		}

		if (vo.getCorpName() != null && vo.getCorpName() != "" && vo.getCorpName().length() > 0) { // 2.所在部门

			Pattern pattern = Pattern.compile("^.*" + vo.getCorpName() + ".*$", Pattern.CASE_INSENSITIVE);

			query.addCriteria(Criteria.where("corpName").regex(pattern));

		}
		/*
		 * 如果"createTime"在query里面出现两次，就会报错，所以日期区间要分三种情况来写。 you can't add a
		 * second 'createTime' criteria. Query already contains '{ "createTime"
		 * : { "$gte" : { "$date" : "2017-05-19T16:00:00.000Z"}}}'
		 */
		if (vo.getBeginTime() != null && vo.getEndTime() != null) {// 3.开始时间和结束时间

			query.addCriteria(Criteria.where("createTime").gte(vo.getBeginTime()).lte(vo.getEndTime()));
		}
		if (vo.getBeginTime() != null && vo.getEndTime() == null) {// 3.开始时间
																	// gte是大于等于

			query.addCriteria(Criteria.where("createTime").gte(vo.getBeginTime()));
		}

		if (vo.getEndTime() != null && vo.getBeginTime() == null) {// 4.结束时间，lte小于等于

			query.addCriteria(Criteria.where("createTime").lte(vo.getEndTime()));
		}

		if (vo.getOperateIp() != null && vo.getOperateIp() != "" && vo.getOperateIp().length() > 0) {

			Pattern pattern = Pattern.compile("^.*" + vo.getOperateIp() + ".*$", Pattern.CASE_INSENSITIVE);

			query.addCriteria(Criteria.where("operateIp").regex(pattern));
		}
		
		query.with(new Sort(new Order(Direction.DESC,"createTime"))); 
		
		return mongoClient.getPage(query, page, LogOperateVo.class);
	}

	// 将LogLoginVo中的endTimeString/beginTimeString转换格式并赋值给endTime/beginTime
	private void setTimeFromString(LogOperateVo vo) {

		if (vo.getEndTimeString() != null && vo.getEndTimeString() != "" && vo.getEndTimeString().length() > 0) {
			vo.setEndTime(getDateFromLocalDateTime(getLocalDateTimeForString(vo.getEndTimeString()).plusDays(1)));
		}

		// 结束日期要增加一天，下一天的零点
		if (vo.getBeginTimeString() != null && vo.getBeginTimeString() != "" && vo.getBeginTimeString().length() > 0) {
			vo.setBeginTime(getDateFromLocalDateTime(getLocalDateTimeForString(vo.getBeginTimeString())));
		}

	}

	/**
	 * 
	 * @param strDate
	 *            8位数字（字符串格式）
	 * @return 将8位字符串数字转换为日期格式，如：20121212-->2012.12.12。
	 *         如果输入的字符串格式不正确或者为null,输出日期为2017.1.1
	 */
	private LocalDateTime getLocalDateTimeForString(String strDate) {

		Pattern p = Pattern.compile("[^0-9]");

		Matcher numMat = p.matcher(strDate);

		String strDateNum = numMat.replaceAll("").trim();// 将strDate变为纯数字组合

		if (strDateNum == null || strDateNum == "" || strDateNum.length() == 0) {

			return null; // 如果传入为空，则返回空值

		}

		LocalDateTime localDateTime = null;

		Pattern pattern = Pattern.compile("[0-9]{8}"); // 正则，8位纯数字

		Matcher isNum8 = pattern.matcher(strDateNum);

		if (isNum8.matches()) { // 如果字符串为，8位纯数字，则添加时分秒，并转换为LocalDateTime格式的时间

			strDateNum += "000000";

			localDateTime = LocalDateTime.parse(strDateNum, DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));

		} else {

			localDateTime = LocalDateTime.of(2017, 1, 1, 0, 0); // 字符串不是8位数字，则设置时间为2017.1.1

		}

		return localDateTime;
	}

	private Date getDateFromLocalDateTime(LocalDateTime localDateTime) {
		// 将LocalDateTime转换为Date格式输出
		ZoneId zone = ZoneId.systemDefault();

		Instant instant = localDateTime.atZone(zone).toInstant();

		Date date = Date.from(instant);

		return date;
	}

}
